#include <stdio.h>
#include <cassert>
#include <string.h>
#include <inttypes.h>

using namespace std;
#include "cbp3_def.h"
#include "cbp3_framework.h"

#include <map>

// last value used, infinite memory

map< uint32_t, uint32_t > previous;

void PredictorInit() {
    previous.clear();
}

void PredictorReset() {
    previous.clear();
    printf("Predictor: last value (local predictor), Cost: INFINITE memory\n");
}

void PredictorRunACycle() {
    // get info about what uops are processed at each pipeline stage
    const cbp3_cycle_activity_t *cycle_info = get_cycle_info();

    // make prediction at fetch stage
    for (int i = 0; i < cycle_info->num_fetch; i++) {
        uint32_t fe_ptr = cycle_info->fetch_q[i];
        const cbp3_uop_dynamic_t *uop = &fetch_entry(fe_ptr)->uop;

        if ( uop->type & IS_BR_CONDITIONAL ) {
            //if( previous.find( uop->pc ) == previous.end() )
            //    assert(report_pred(fe_ptr, false, true )); // this actually works worse!?
            //else
                assert(report_pred(fe_ptr, false, previous[ uop->pc ] ));
        }else if ( uop->type & IS_BR_INDIRECT ) {
            assert(report_pred(fe_ptr, false, previous[ uop->pc ]));
        }
    }

    for (int i = 0; i < cycle_info->num_retire; i++) {
        uint32_t rob_ptr = cycle_info->retire_q[i];
        const cbp3_uop_dynamic_t *uop = &rob_entry(rob_ptr)->uop;

        if ( uop->type & IS_BR_CONDITIONAL) {
            previous[ uop->pc ] = uop->br_taken;
        }else if ( uop->type && IS_BR_INDIRECT ){
            previous[ uop->pc ] = uop->br_target;
        }
    }
}

void PredictorRunEnd() {
    // nothing
}

void PredictorExit() {
    // nothing
}
